/*
 * Copyright (C) 2008
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.sca4idea.providers;

import com.googlecode.sca4idea.SCABundle;
import com.googlecode.sca4idea.psi.SCAComponentTagPsiElement;
import com.googlecode.sca4idea.psi.SCACompositeComponentTagPsiElement;
import com.googlecode.sca4idea.psi.SCAJavaComponentTagPsiElement;
import com.googlecode.sca4idea.psi.SCAWebappComponentTagPsiElement;
import static com.googlecode.sca4idea.references.SCAReferencesUtil.componentElementDetailAttribute;
import com.googlecode.sca4idea.references.SCDLLocationReferenceProvider;
import com.googlecode.sca4idea.references.SCDLResourceReferenceProvider;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.Nullable;

/**
 * Vanilla implementation of the SCA Provider, implementing only those features documented in the formal SCA
 * specifications.
 */
public class VanillaSCAProvider implements SCAProvider {
    public static final String SCA_NS = "http://www.osoa.org/xmlns/sca/1.0";

    public static VanillaSCAProvider INSTANCE = new VanillaSCAProvider();

    private VanillaSCAProvider() {
    }

    public String getId() {
        return "vanilla";
    }

    public String getDisplayName() {
        return SCABundle.message("provider.vanilla.name");
    }

    public void registerReferences(ProviderReferenceRegistrar registry) {
        // Composite implementations wired through classpath navigation
        SCDLResourceReferenceProvider scdlResourceReferenceProvider = new SCDLResourceReferenceProvider();
        scdlResourceReferenceProvider.setSoft(false);
        registry.registerReferenceProvider(
                componentElementDetailAttribute("implementation.composite", "scdlResource"),
                scdlResourceReferenceProvider);

        // Composite implementations wired through file-system navigation
        SCDLLocationReferenceProvider scdlLocationReferenceProvider = new SCDLLocationReferenceProvider();
        scdlLocationReferenceProvider.setSoft(false);
        registry.registerReferenceProvider(
                componentElementDetailAttribute("implementation.composite", "scdlLocation"),
                scdlLocationReferenceProvider);

        // Java Implementations
        JavaClassReferenceProvider classReferenceProvider = new JavaClassReferenceProvider(registry.getProject());
        classReferenceProvider.setSoft(false);
        registry.registerReferenceProvider(
                componentElementDetailAttribute("implementation.java", "class"),
                classReferenceProvider);
    }

    @Nullable
    public SCAComponentTagPsiElement getPSIElementForTag(XmlTag componentTag) {
        // Java components
        XmlTag[] javaImpl = componentTag.findSubTags("implementation.java", SCA_NS);
        if (javaImpl.length > 0) {
            return new SCAJavaComponentTagPsiElement(componentTag, javaImpl[0]);
        }

        // Composite components
        XmlTag[] compositeImpl = componentTag.findSubTags("implementation.composite", SCA_NS);
        if (compositeImpl.length > 0) {
            // Attempt to find the resource that defines us
            String scdlResource = compositeImpl[0].getAttributeValue("scdlResource");
            String scdlLocation = compositeImpl[0].getAttributeValue("scdlLocation");

            if (scdlResource != null && StringUtil.isNotEmpty(scdlResource)) {
                return new SCACompositeComponentTagPsiElement(componentTag, scdlResource, true);
            } else if (scdlLocation != null && StringUtil.isNotEmpty(scdlLocation)) {
                return new SCACompositeComponentTagPsiElement(componentTag, scdlLocation, false);
            }
        }

        // Web components
        XmlTag[] webImpl = componentTag.findSubTags("implementation.web", SCA_NS);
        if (webImpl.length > 0) {
            return new SCAWebappComponentTagPsiElement(componentTag);
        }

        return null;
    }

    public boolean isAlwaysActive() {
        return true;
    }
}
